// Copyright 2009 Pigasus.
// GNU GPL v2.
// Author: John Zhang and Jordan Rupprecht.
//
// Defines the types supported by Pigasus. Particularly the classes representing
// the types for storage into Pigasus lists and maps. The following classes are
// defined:
//   List
//   Map
//   File

#ifndef PIGASUS_TYPES_H_
#define PIGASUS_TYPES_H_

#include <map>
#include <string>
#include <vector>

using namespace std;

// String representations of the types. That is, this is what is returned after
// a user uses the Pigasus 'typeof' expression.
const string kIntType = "int";
const string kFloatType = "float";
const string kStringType = "string";
const string kListType = "list";
const string kMapType = "map";
const string kFileType = "file";
const string kNullType = "null";

// Given a pointer and the type as a string, delete it from memory. This
// includes the Pigasus specific types also.
void DeleteElement(string type, void* ptr);

class List;
class Map;
class File;

List NewList(const int &v);
List NewList(const double &v);
List NewList(const string &v);
List NewList(const List &v);
List NewList(const Map &v);
List NewList(const File &v);

// Represents a Pigasus list, stored as a vector of pairs, where the first
// element is the type (stored as a string) and the second is the pointer to
// the actual value. You may declare:
//   List my_list;
// You may also use:
//   List *my_list = new List();
// And remember to clean up after yourself:
//   delete my_list;
class List {
  // Elements of the list are stored as pairs, with the first being the type,
  // and the second being a pointer to the element stored in memory.
  vector< pair<string, void*> > value;

  // Copy.
  void CopyIntoThis(const List &v);

 public:
  // Empty constructor.
  List();
  // Overload copy constructor.
  List(const List &v);
  // Overload copy operator.
  List& operator=(const List &v);
  
  // Destructor will also go through the values and delete everything in the
  // List (recursively if necessary).
  ~List();

  // Creates a new List in memory with copies (not just pointers) of the
  // elements.
  List* Clone();
  // Returns a new List by value with the same values as this.
  List CloneValue();

  // Returns a pointer to the element stored at the specified index. 
  void* Get(int index);
  // Operator associated with Get. So for List v, v[1] is equivalent to Get(1).
  void* operator[](const int &index);

  // Appends an element to the end of the list. Remember to pass the reference
  // for Pigasus-specific types.
  void Append(const int &v);
  void Append(const double &v);
  void Append(const string &v);
  void Append(const List &v);
  void Append(const Map &v);
  void Append(const File &v);
  
  // Replaces the element at the given index. Remember to pass the reference for
  // Pigasus-specific types. TODO: decide how to handle the error if the
  // specified index is out of bounds. Also, the existing element stored at
  // the index is deleted. (Since it's a 'local' copy, it shouldn't affect
  // anything else).
  void Set(int index, const int &v);
  void Set(int index, const double &v);
  void Set(int index, const string &v);
  void Set(int index, const List &v);
  void Set(int index, const Map &v);
  void Set(int index, const File &v);
  
  // Returns a new List which contains the elements of the current List, plus
  // the elements of a specified List at the end.
  List Concatenate(const List &w);
  // Operator associated with Concatenate. So for Lists a, b, c, the following are
  // equivalent: c = a + b and c = a.Concatenate(b).
  List operator+(const List &v);

  // Returns number of objects in list.
  int GetSize();

  // Returns the type of the element stored at the index.
  string GetType(int index);
};

// Represents a Pigasus map, stored as a map mapping strings to pairs where the
// first elements is the type of the value (stored as a string) and the second
// element is a pointer to the value itself. If you use a pointer, please clean
// up afterwards:
//   Map *my_map = new Map();
//   delete my_map;
// Of course, you could simply declare:
//   Map my_map;
class Map {
  // Elements of the Map are stored as C++ maps, which map a string key to a
  // pair, with the first being the type and the second being a pointer to the
  // element stored in memory.
  map< string, pair<string, void*> > value;

  // Copy.
  void CopyIntoThis(const Map &v);

 public:
  // Empty constructor.
  Map();
  // Overload copy constructor.
  Map(const Map &v);
  // Overload copy operator.
  Map& operator=(const Map &v);

  // Maps with an initial element.
  Map(const string &key, const int &v);
  Map(const string &key, const double &v);
  Map(const string &key, const string &v);
  Map(const string &key, const List &v);
  Map(const string &key, const Map &v);
  Map(const string &key, const File &v);
  // Deletes all elements in Map, recursively if necessary.
  ~Map();

  // Returns a pointer to a new Map in memory, with copies of the current Map's
  // elements.
  Map* Clone();
  // Return a copy of the current Map by value.
  Map CloneValue();

  // Returns a pointer to the element stored at key.
  void* Get(string key);
  // Associated with Get.
  void* operator[](const string &key);

  // Sets the element at key. Replaces an existing element if it exists (and the
  // existing element is deleted from memory). Like List, remember to pass in
  // the reference if using Pigasus-specific types.
  void Set(const string &key, const int &v);
  void Set(const string &key, const double &v);
  void Set(const string &key, const string &v);
  void Set(const string &key, const List &v);
  void Set(const string &key, const Map &v);
  void Set(const string &key, const File &v);  

  // Returns a new Map with all the mappings of the current Map, plus all the
  // mappings of the specified Map. The specified Map will be given preference
  // when keys exist in both the current and specified Maps.
  Map Concatenate(const Map &v);
  // Operator associated with concatenate.
  Map operator+(const Map &v);

  // Returns the number of objects in the map.
  int GetSize();

  // Returns the type of the element at key.
  string GetType(const string &key);

  // Returns a List of the keys.
  List GetKeys();
};

// Represents a Pigasus file. Simply a string, indicating the filename.
// Deconstructor for file doesn't do much, but is kept for consistency. 
// TODO: Eventually, it may be necessary that filename be converted into the
// absolute path.
class File {
  string filename;

 public:
  File();
  File(string filename_);
  ~File();

  File* Clone();
  File CloneValue();

  string Filename();
};

#endif  // PIGASUS_TYPES_H_

